﻿package com.singlenotion.form 
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.FocusEvent;
	import flash.events.MouseEvent;
	import flash.text.AntiAliasType;
	import flash.text.Font;
	import flash.text.TextField;
	import flash.text.TextFieldType;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	
	/**
	 * ...
	 * @author Adam Jowett (Single Notion)
	 */
	public class FormField extends MovieClip
	{
		private var _fieldType:String;
		private var _fieldWidth:Number;
		private var _fieldHeight:Number;
		private var _bgColour:int;
		private var _borderColour:int;
		private var _errorColour:int;
		private var _txtColour:int;
		private var _fontName:String;
		private var _fontSize:Number;
		private var _focusColour:int;
		private var _defaultText:String;
		
		private var _bg:FormFieldBackground;
		private var _txtField:TextField;
		private var _valid:Boolean;
		private var _selectable:Boolean;
		private var _length:int;
		private var _text:String;
		private var _txtFormat:TextFormat;
		
		public function FormField(	$type:String, $fieldWidth:Number, $fieldHeight:Number, $fontName:String, $fontSize:Number = 14, $txtColour:int = 0x000000, 
									$bgColour:int = 0xFFFFFF, $borderColour:int = 0x000000,	$focusColour:int = 0xD0E925, $errorColour:int = 0x990000, $defaultText:String = "") 
		{
			_fieldType = $type;
			_fieldWidth = $fieldWidth;
			_fieldHeight = $fieldHeight;
			_bgColour = $bgColour;
			_borderColour = $borderColour;
			_errorColour = $errorColour;
			_txtColour = $txtColour;
			_fontName = $fontName;
			_fontSize = $fontSize;
			_focusColour = $focusColour;
			_defaultText = $defaultText;
			
			init(null);
		}
		
		private function init($e:Event):void 
		{
			addEventListener(Event.REMOVED_FROM_STAGE, destroy, false, 0, true);
			addBackground();
			addField();
		}
		
		private function addBackground():void
		{
			_bg = new FormFieldBackground(_fieldWidth, _fieldHeight, _bgColour, _borderColour, _focusColour, _errorColour);
			addChild(_bg);
		}
		
		private function addField():void
		{
			_txtField = new TextField();
			_txtFormat = new TextFormat();
			
			_txtFormat.color = _txtColour;
			_txtFormat.font = _fontName;
			_txtFormat.size = _fontSize;
			
			switch (_fieldType) {
				case FormFieldType.NUMERIC:
				_txtField.restrict = "0-9";
				break;
				case FormFieldType.PHONE_AU:
				_txtField.restrict = "0-9";
				_txtField.maxChars = 10;
				break;
				case FormFieldType.POSTCODE_AU:
				_txtField.restrict = "0-9";
				_txtField.maxChars = 4;
				break;
				case FormFieldType.DAY:
				_txtField.maxChars = 2;
				_txtFormat.align = TextFormatAlign.CENTER;
				break;
				case FormFieldType.MONTH:
				_txtField.maxChars = 2;
				_txtFormat.align = TextFormatAlign.CENTER;
				break;
				case FormFieldType.YEAR:
				_txtField.maxChars = 4;
				_txtFormat.align = TextFormatAlign.CENTER;
				break;
			}
					
			_txtField.defaultTextFormat = _txtFormat;
			_txtField.embedFonts = true;
			_txtField.type = TextFieldType.INPUT;
			_txtField.textColor = _txtColour;
			_txtField.border = false;
			_txtField.background = false;
			_txtField.antiAliasType = AntiAliasType.ADVANCED;
			_txtField.width = _fieldWidth;
			_txtField.height = _fieldHeight;
			_txtField.y = 2;
			_txtField.displayAsPassword = (_fieldType == FormFieldType.PASSWORD);
			
			_txtField.text = _defaultText;
			
			_txtField.addEventListener(Event.CHANGE, validate, false, 0, true);
			
			addChild(_txtField);
			
			// wait to be added to stage so that we have a parent to add a listener to for mouse down
			addEventListener(Event.ADDED_TO_STAGE, turnOn, false, 0, true);
		}
		
		private function turnOn($e:Event):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, turnOn);
			selectable = true;
		}
		
		public function validate($e:* = null):Boolean 
		{
			if (_txtField.text == "") _txtField.text = _defaultText;
			
			dispatchEvent(new FocusEvent(FocusEvent.FOCUS_OUT, true, true));
			dispatchEvent(new Event(FormFieldEvent.MANUAL_VALIDATE, true, true));
			
			_bg.focus = false;
			
			switch (_fieldType) {
				case FormFieldType.EMAIL:
				valid = FormValidationUtil.isEmail(_txtField.text);
				break;
				case FormFieldType.PASSWORD:
				valid = (_txtField.length > 3);
				break;
				case FormFieldType.POSTCODE_AU:
				valid = (_txtField.length == 4);
				break;
				case FormFieldType.PHONE_AU:
				valid = (_txtField.length == 10);
				break;
				case FormFieldType.CREDIT_CARD:
				valid = (FormValidationUtil.isCreditCard(_txtField.text));
				default:
				valid = (_txtField.length > 0);
				break
			}
			
			return(valid);
		}
		
		private function highlight($e:FocusEvent):void 
		{
			dispatchEvent(new FocusEvent(FocusEvent.FOCUS_IN, true, true));
			_bg.focus = true;
			if (_txtField.text == _defaultText) _txtField.text = "";
		}
		
		private function destroy($e:Event):void 
		{
			removeEventListener(Event.REMOVED_FROM_STAGE, destroy);
			_txtField.removeEventListener(Event.SELECT, highlight);
		}
		
		public function clear():void
		{
			_txtField.text = "";
		}
		
		public function get valid():Boolean { return _valid; }
		
		public function set valid(value:Boolean):void 
		{
			_valid = value;
			_bg.valid = _valid;
			
			if (!_valid) {
				dispatchEvent(new Event(FormFieldEvent.VALID_ERROR, true, true));
			} else {
				dispatchEvent(new Event(FormFieldEvent.VALID_CONFIRM, true, true));
			}
		}
		
		public function get selectable():Boolean { return _selectable; }
		
		public function set selectable(value:Boolean):void 
		{
			if (parent == null) throw(new Error("Cannot set selectable property until after field has been added to display list"));
			
			_selectable = value;
			
			_txtField.selectable = _selectable;
			_txtField.visible = _selectable;
			
			if (_selectable) {
				_txtField.addEventListener(FocusEvent.FOCUS_IN, highlight, false, 0, true);
				_txtField.addEventListener(FocusEvent.FOCUS_OUT, validate, false, 0, true);
			} else {
				_bg.reset();
				_txtField.removeEventListener(FocusEvent.FOCUS_IN, highlight);
				_txtField.removeEventListener(FocusEvent.FOCUS_OUT, validate);
			}
		}
		
		public function get length():int { return _txtField.length; }
		
		public function set text($val:String):void 
		{
			_txtField.text = $val;
		}
		
		public function get text():String { return _txtField.text; }
		
		public function get field():TextField { return _txtField; }
	}
}